package com.gray.blog.common.util.thread;

import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;
import java.util.concurrent.TimeUnit;
import java.util.function.BiFunction;
import java.util.function.Supplier;
import lombok.extern.slf4j.Slf4j;

/**
 * Created  By zhoux 2020/04/24
 **/
@Slf4j
public class CompletableFactory<T> {

    public CompletableFuture runAsync(Runnable runnable, Executor executor) {
        return CompletableFuture.runAsync(runnable, executor).exceptionally(e -> {
            // 这里相当于catch
            log.warn("CompletableFactory.runAsync error e:{}", e);
            return null;
        });
    }

    public CompletableFuture<T> supplyAsync(Supplier<T> supplier, Executor executor) {
        return CompletableFuture.supplyAsync(supplier, executor).exceptionally(e -> {
            // 这里相当于catch
            log.warn("CompletableFactory.supplyAsync error e:{}", e);
            return null;
        });
    }

    public void thenCombine(CompletableFuture firstFuture, CompletableFuture secondFuture, BiFunction biFunction) {
        CompletableFuture lastFuture = firstFuture.thenCombine(secondFuture, biFunction);
        lastFuture.join();
    }


    public static void main(String args[]) {
        // 第一步 (exceptionally 相当于 catch)
        CompletableFactory<Void> a = new CompletableFactory<>();
        CompletableFuture t1 = a.runAsync(() -> {
            System.out.println("T1");
            sleep(1, TimeUnit.SECONDS);
            System.out.println("T2");
            sleep(15, TimeUnit.SECONDS);
            int i = 1/0;
        }, SysUserThreadPoolUtils.service);

        // 第二步
        CompletableFuture t2 = a.runAsync(() -> {
            System.out.println("T3");
            sleep(1, TimeUnit.SECONDS);

            System.out.println("T4");
            sleep(1, TimeUnit.SECONDS);

            System.out.println("T5");
            sleep(1, TimeUnit.SECONDS);
        }, SysUserThreadPoolUtils.service);

        a.thenCombine(t1, t2, (__, ___) -> {
            System.out.println("T6");
            return null;
        });

        System.out.println("T7");

    }

    private static void sleep(int t, TimeUnit u) {
        try {
            u.sleep(t);
        } catch (Exception ignored) {

        }
    }

}
